#include <stdint.h>
#include <stdio.h>
#include <limits.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/ioctl.h>
#include <string.h>
#include <pthread.h>
#include "global.h"
#include "ietAiLib.h"
#include "prt_log.h"

#define LIB_VERSION(a,b,c)                  ((a << 24) + (b << 16) + (c))

#define AI_MAX_CHANNEL      32              /* AI 最大通道数 */
#if (HARD_VER == 0)
#define AI_AIM_CHANNEL      16              /* AI 在 AI 模块中通道数 */
#define AI_ACM_CHANNEL      9               /* AI 在 AC 模块中通道数 */
#define AI_IEPEM_CHANNEL    16              /* AI 在 IEPE 模块中通道数 */
#elif (HARD_VER == 1)
#define AI_AIM_CHANNEL      16              /* AI 在 AI 模块中通道数 */
#define AI_ACM_CHANNEL      9               /* AI 在 AC 模块中通道数 */
#define AI_IEPEM_CHANNEL    16              /* AI 在 IEPE 模块中通道数 */
#endif

#define AI_DRV_NAME         "pcie_ai"       /* AI 驱动名称 */
#define AI_UV_2_V           1000000         /* AI uV -> V */
#define AI_UV_2_MV          1000            /* AI uV -> V */
#define AI_MAX_SAMP_RATE    100000          /* AI 最大采样率, Hz */
#define AI_MAX_IRQ_RATE     100000          /* AI 最大中断频率, Hz */
#define AI_MAX_SLIDE_WIN    32              /* AI 滑动平均窗口最大值 */
#define AI_SAMP_RESISTOR    200             /* AI 采样电阻, Ω */

#define AI_DEF_DMA_SIZE     (64 * 1024)     /* AI DMA 大小 128KByte */
#define AI_PRINT_BYTES      32              /* AI DMA 预留数据长度 */
#define AI_RANGE_10V_LSB    305             /* 305uV */
#define AI_RANGE_2V5_LSB    76              /* 76uV */
#define AI_RANGE_5V_LSB     152             /* 152uV */

#define AI_ACM_SAMP_OHM     20              /* AI AC 模块 采样电阻, Ω */
#define AI_ACM_UCH_NUM      6               /* AI AC 模块 U 通道 数量 */
#define AI_ACM_UCH_KVAL     182             /* AI AC 模块 U 通道 计算系数 */
#define AI_ACM_ICH_KVAL     100.8           /* AI AC 模块 I 通道 计算系数 */

/* IOCTL 命令定义 */
#define IOCTL_AI_MAGIC                      'P'                                         /* 标识设备驱动 */
#define IOCTL_AI_SET_MODE                   _IOW(IOCTL_AI_MAGIC, 1, uint8_t)            /* 配置 AI 模式 */
#define IOCTL_AI_SET_OSR                    _IOW(IOCTL_AI_MAGIC, 2, uint8_t)            /* 配置 AI 过采样 */
#define IOCTL_AI_SET_SAMP_RATE              _IOW(IOCTL_AI_MAGIC, 3, uint32_t)           /* 配置 AI 采样频率 */
#define IOCTL_AI_SET_IRQ_RATE               _IOW(IOCTL_AI_MAGIC, 4, uint16_t)           /* 配置 AI 中断频率 */
#define IOCTL_AI_SET_SLID_WIN               _IOW(IOCTL_AI_MAGIC, 5, uint16_t)           /* 配置 AI 滑动平均窗口 */
#define IOCTL_AI_SET_RANGE                  _IOW(IOCTL_AI_MAGIC, 6, uint8_t)            /* 配置 AI 量程 */
#define IOCTL_AI_GET_VAL                    _IOR(IOCTL_AI_MAGIC, 7, int32_t)            /* 获取 AI 数值 */
#define IOCTL_AI_WAIT_TIM_IRQ               _IOR(IOCTL_AI_MAGIC, 8, int32_t *)          /* 等待 AI 定时中断 */
#define IOCTL_AI_START                      _IO(IOCTL_AI_MAGIC,  9)                     /* 开始 AI 采集 */
#define IOCTL_AI_STOP                       _IO(IOCTL_AI_MAGIC,  10)                    /* 停止 AI 采集 */

#define IOCTL_AI_GET_DRV_VERSION            _IOR(IOCTL_AI_MAGIC, 101, uint32_t)         /* 获取驱动版本号 */
#define IOCTL_AI_GET_FPGA_VERSION           _IOR(IOCTL_AI_MAGIC, 102, uint32_t)         /* 获取 FPGA 版本号 */

/* 应用层 */
enum AiMode {
    AI_MOD_NORMAL           = 0,            /* 普通模式 */
    AI_MOD_IRQ              = 1,            /* 中断模式 */
    AI_MOD_DMA              = 2,            /* DMA 模式 */
    AI_MOD_RAW              = 3,            /* 原始数据 */
};
enum AiRange {
    AI_RANGE_10V            = 0,            /* ±10V */
    AI_RANGE_2V5            = 1,            /* ±2.5V */
    AI_RANGE_5V             = 2,            /* ±5V */
};
enum AiValType {
    AI_VAL_VOLTAGE          = 0,            /* 电压值 */
    AI_VAL_CURRENT          = 1,            /* 电流值 */
};

/* 驱动层*/
enum AiDevMode {
    AI_DEV_MOD_NORMAL       = 0,            /* 普通模式 */
    AI_DEV_MOD_IRQ          = 1,            /* 中断模式 */
    AI_DEV_MOD_DMA          = 2,            /* DMA 模式 */
    AI_DEV_MOD_RAW          = 3,            /* 原始数据 */
};
enum AiDevRange {
    AI_DEV_RANGE_10V        = 0,            /* ±10V */
    AI_DEV_RANGE_2V5        = 1,            /* ±2.5V */
    AI_DEV_RANGE_5V         = 2,            /* ±5V */
};

struct ThreadCtrl_t {
    char name[64];                          /* 线程名 */
    pthread_t id;                           /* 线程标识 */
};

struct AiDev_t {
    void *parent;                                           /* 父指针 */
    char name[32];                                          /* 设备名 */
    uint8_t index;                                          /* 设备号 */

    uint8_t setRange;                                       /* 量程 */
    int32_t rawVal;                                         /* 原始值 */
    double val;                                             /* 数值 */

    int fd;                                                 /* 文件 */
    char path[PATH_MAX];                                    /* 路径 */
};
struct AiCtrl_t {
    char name[16];                                          /* 控制器名 */
    uint8_t num;                                            /* 设备数量 */
    uint8_t maxNum;                                         /* 最大数量 */
    struct AiDev_t dev[AI_MAX_CHANNEL];                     /* 设备描述 */

    uint8_t type;                                           /* 模块类型 */
    uint8_t setMode;                                        /* 模式 */
    uint16_t setSampRate;                                   /* 采样频率 */
    uint16_t setIrqRate;                                    /* 中断频率 */
    uint16_t setSlidWin;                                    /* 滑动平均窗口 */
    int32_t rawVal[AI_MAX_CHANNEL];                         /* 原始值 */
    double val[AI_MAX_CHANNEL];                             /* 数值 */
    uint32_t drvVer;                                        /* 驱动 版本号 */
    uint32_t fpgaVer;                                       /* FPGA 版本号 */
    uint32_t libVer;                                        /* 动态库 版本号 */

    struct ThreadCtrl_t irqThread;                          /* 中断线程 */
    struct ThreadCtrl_t dmaThread;                          /* DMA 线程 */
    void (*irqCallback)(double *data);                      /* 中断回调函数 */
    void (*dmaCallback)(uint8_t *buf);                      /* DMA 回调函数 */
};
/* AI 控制器 */
static struct AiCtrl_t AiCtrl;

/* 获取设备数量 */
static uint8_t AIMGetDevNum(int type)
{
    uint8_t num = 0;

    switch (type) {
    case IET_ECU:
    case IET_DI:
    case IET_DO:
        goto err_retrun;
    case IET_AI:
        num = AI_AIM_CHANNEL;
        break;
    case IET_AO:
    case IET_PI:
    case IET_SOE:
        goto err_retrun;
    case IET_AC:
        num = AI_ACM_CHANNEL;
        break;
    case IET_PT100:
        goto err_retrun;
    case IET_IEPE:
        num = AI_IEPEM_CHANNEL;
        break;
    default:
        prt_erro("Invalid type %d for %s\n", type, __func__);
        return 0;
    }
    prt_info("%s get %d device\n", __func__, num);

    return num;

err_retrun:
    prt_erro("%s get no device\n", __func__);

    return 0;
};

/* 中断接收线程 */
static void *AIMIrqThreadFunc(void *arg)
{
    struct AiDev_t *pdev = (struct AiDev_t *)arg;
    struct AiCtrl_t *pctrl = (struct AiCtrl_t *)(pdev->parent);
    int ret = 0;
    uint8_t i = 0;

    /* 检查参数 */
    if (!pdev || (pdev->fd == 0)) {
        prt_erro("Invalid parameters for %s\n", __func__);
        return NULL;
    }

    prt_dbug("Start %s %s\n", pctrl->name, __func__);
    while (1) {
        /* 等待 AI 定时中断 */
        ret = ioctl(pdev->fd, IOCTL_AI_WAIT_TIM_IRQ, &pctrl->rawVal[0]);
        if (ret < 0) {
            prt_erro("Wait AI timer irq failed\n");
            return NULL;
        }
        for (i = 0; i < pctrl->num; i++) {
            pctrl->val[i] = 1.0 * pctrl->rawVal[i] / AI_UV_2_V;
            prt_info("AI %2d val %.6lfV\n", i, pctrl->val[i]);
        }
        if (pctrl->irqCallback != NULL) {
            pctrl->irqCallback(&pctrl->val[0]);
            prt_dbug("Trigger AI timer irq\n");
        } else {
            prt_erro("Trigger AI timer irq, but no callback func\n");
        }
    }
    prt_dbug("Return %s %s\n", pctrl->name, __func__);

    return NULL;
}

/* DMA 接收线程 */
static void *AIMDmaThreadFunc(void *arg)
{
    struct AiDev_t *pdev = (struct AiDev_t *)arg;
    struct AiCtrl_t *pctrl = (struct AiCtrl_t *)(pdev->parent);
    uint8_t buffer[AI_DEF_DMA_SIZE];
    ssize_t readCnt = 0;
    int offset = 0;
    int i = 0;
    int j = 0;
    double value = 0.0;
    uint32_t u32_val = 0;

    /* 检查参数 */
    if (!pdev || (pdev->fd == 0)) {
        prt_erro("Invalid parameters for %s\n", __func__);
        return NULL;
    }

    prt_dbug("Start %s %s\n", pctrl->name, __func__);
    while (1) {
        readCnt = read(pdev->fd, buffer, AI_DEF_DMA_SIZE);
        if (readCnt < 0) {
            if (errno == EINTR) {
                prt_warn("Wait %s read data interrupted", pctrl->name);
                break;
            }
        } else if (readCnt < AI_DEF_DMA_SIZE) {
            prt_warn("Read %zd bytes, not %d bytes\n", readCnt, AI_DEF_DMA_SIZE);
        } else if (readCnt == AI_DEF_DMA_SIZE) {
            memcpy(&u32_val, &buffer[10], sizeof(u32_val)); 
            prt_info("daq_acquire=%d\n", u32_val);
            if (pctrl->num % 4 != 0) {
                prt_warn("Channel number %d%%4 != 0\n", pctrl->num);
            }
            for (offset = AI_PRINT_BYTES; offset < readCnt; offset += 2 * pctrl->num) {
                if ((offset + 2 * pctrl->num) > readCnt) {
                    prt_dbug("Left %zd channel data, should be %d\n", 
                             ((offset + 2 * pctrl->num) - readCnt) / 2, pctrl->num);
                    break;
                }
                prt_dbug("--- Block %d ---\n", (offset - AI_PRINT_BYTES) / (2 * pctrl->num) + 1);
                for (i = 0; i < pctrl->num; i++) {
                    j = offset + i * 2;
                    // 组合两个字节为16位数据（小端模式）
                    int16_t raw_value = ((int16_t)buffer[j + 1] << 8) | buffer[j];
                    
                    // 应用转换公式
                    value = value;
                    if (pdev->setRange == AI_DEV_RANGE_2V5) {
                        value = raw_value * AI_RANGE_2V5_LSB / AI_UV_2_V;
                    } else if (pdev->setRange == AI_DEV_RANGE_5V) {
                        value = raw_value * AI_RANGE_5V_LSB / AI_UV_2_V;
                    } else {
                        value = raw_value * AI_RANGE_10V_LSB / AI_UV_2_V;
                    }
                    prt_dbug("Channel %02d: raw=0x%04x (%5u) -> %.6lfV\n", 
                             i, raw_value, raw_value, value);
                }
            }
            if (pctrl->dmaCallback != NULL) {
                pctrl->dmaCallback(&buffer[AI_PRINT_BYTES]);
                prt_dbug("Trigger AI DMA irq\n");
            } else {
                prt_erro("Trigger AI DMA irq, but no callback func\n");
            }
        }
    }
    prt_dbug("Return %s %s\n", pctrl->name, __func__);

    return NULL;
}

/* 打开设备 */
int AIMOpen(int moduleType)
{
    struct AiCtrl_t *pctrl = &AiCtrl;
    struct AiDev_t *pdev = &pctrl->dev[0];
    int ret = 0;
    uint8_t i = 0;
    int8_t j = 0;

    pctrl->num = AIMGetDevNum(moduleType);
    pctrl->maxNum = AI_MAX_CHANNEL;
    pctrl->type = (uint8_t)moduleType;
    /* 检查参数 */
    if (pctrl->num > pctrl->maxNum) {
        prt_erro("Get AI number %d, max is %d\n", pctrl->num, pctrl->maxNum);
        return -EFAULT;
    }
    /* 生成路径 */
    snprintf(pctrl->name, sizeof(pctrl->name), "%s", AI_DRV_NAME);
    for (i = 0; i < pctrl->num; i++) {
        pdev = &pctrl->dev[i];
        pdev->parent = pctrl;
        snprintf(pdev->name, sizeof(pdev->name), "%s%d", pctrl->name, i);
        pdev->index = i;
        pdev->fd = -ENODEV;
        ret = snprintf(pdev->path, PATH_MAX, "/dev/%s", pdev->name);
        if (ret < 0 || ret >= PATH_MAX) {
            prt_erro("Generate %s path failed\n", pdev->name);
            return -ENAMETOOLONG;
        }
        /* 打开设备 */
        pdev->fd = open(pdev->path, O_RDWR);
        if (pdev->fd < 0) {
            ret = errno;
            prt_erro("Open %s device failed, %s\n", pdev->path, strerror(ret));
            ret = -ret;
            goto err_close_fd;
        }
        prt_dbug("Open %s device success\n", pdev->path);
    }

    pdev = &pctrl->dev[0];
    /* 获取驱动版本号 */
    ret = ioctl(pdev->fd, IOCTL_AI_GET_DRV_VERSION, &pctrl->drvVer);
    if (ret < 0) {
        prt_erro("Get AI driver version 0x%08x failed\n", pctrl->drvVer);
        goto err_close_fd;
    }
    prt_dbug("Get AI driver version 0x%08x\n", pctrl->drvVer);
    /* 获取 FPGA 版本号 */
    ret = ioctl(pdev->fd, IOCTL_AI_GET_FPGA_VERSION, &pctrl->fpgaVer);
    if (ret < 0) {
        prt_erro("Get AI FPGA version 0x%08x failed\n", pctrl->fpgaVer);
        goto err_close_fd;
    }
    prt_dbug("Get AI FPGA version 0x%08x\n", pctrl->fpgaVer);
    pctrl->libVer = LIB_VERSION(AI_VER_MAJOR, AI_VER_MINOR, AI_VER_PATCH);
    prt_dbug("Get AI library version 0x%08x\n", pctrl->libVer);

    return 0;

err_close_fd:
    for (j = i - 1; j >= 0; j--) {
        pdev = &pctrl->dev[j];
        close(pdev->fd);
        pdev->fd = -ENODEV;
    }

    return ret;
}

/* 初始化设备 */
int AIMInit(struct AimParam aimParam)
{
    struct AiCtrl_t *pctrl = &AiCtrl;
    struct AiDev_t *pdev = &pctrl->dev[0];
    struct ThreadCtrl_t *pthread_irq = &pctrl->irqThread;
    struct ThreadCtrl_t *pthread_dma = &pctrl->dmaThread;
    int ret = 0;
    uint8_t i = 0;
    uint8_t mode = 0;

    /* 检查参数 */
    if (pdev->fd == 0 || 
        aimParam.mode < 0 || aimParam.mode > AI_MOD_RAW || 
        aimParam.sampleRate < 0 || aimParam.sampleRate > AI_MAX_SAMP_RATE || 
        aimParam.interruptRate < 0 || aimParam.interruptRate > AI_MAX_IRQ_RATE || 
        aimParam.filtWindow < 0 || aimParam.filtWindow > AI_MAX_SLIDE_WIN) {
        prt_erro("Invalid parameters for %s\n", __func__);
        return -EFAULT;
    }
    /* 配置模式 */
    switch (aimParam.mode) {
    case AI_MOD_NORMAL:
        mode = AI_DEV_MOD_NORMAL;
        break;
    case AI_MOD_IRQ:
        mode = AI_DEV_MOD_IRQ;
        break;
    case AI_MOD_DMA:
        mode = AI_DEV_MOD_DMA;
        break;
    case AI_MOD_RAW:
        mode = AI_DEV_MOD_RAW;
        break;
    default:
        prt_erro("Invalid mode %d for %s\n", aimParam.mode, __func__);
        ret = -EFAULT;
        goto err_return;
    }
    pctrl->setMode = mode;
    pctrl->setSampRate = aimParam.sampleRate;
    pctrl->setIrqRate = aimParam.interruptRate;
    pctrl->setSlidWin = aimParam.filtWindow;
    if (pctrl->setMode == AI_DEV_MOD_IRQ) {
        /* 创建线程 */
        snprintf(pthread_irq->name, sizeof(pthread_irq->name), "%s%s", "irq_", pdev->name);
        ret = pthread_create(&pthread_irq->id, NULL, AIMIrqThreadFunc, pdev);
        if (ret != 0) {
            prt_erro("Create %s thread failed\n", pthread_irq->name);
            ret = -ret;
            goto err_return;
        } else {
            prt_dbug("Create %s thread success\n", pthread_irq->name);
        }
    } else if (pctrl->setMode == AI_DEV_MOD_DMA) {
        /* 创建线程 */
        snprintf(pthread_dma->name, sizeof(pthread_dma->name), "%s%s", "dma_", pdev->name);
        ret = pthread_create(&pthread_dma->id, NULL, AIMDmaThreadFunc, pdev);
        if (ret != 0) {
            prt_erro("Create %s thread failed\n", pthread_dma->name);
            ret = -ret;
            goto err_return;
        } else {
            prt_dbug("Create %s thread success\n", pthread_dma->name);
        }
    } else {
        /* 取消线程 */
        if (pthread_irq->id != 0) {
            pthread_cancel(pthread_irq->id);
            pthread_irq->id = 0;
        }
        if (pthread_dma->id != 0) {
            pthread_cancel(pthread_dma->id);
            pthread_dma->id = 0;
        }
    }
    /* 配置 AI 模式 */
    ret = ioctl(pdev->fd, IOCTL_AI_SET_MODE, &pctrl->setMode);
    if (ret < 0) {
        prt_erro("Set AI mode %d failed\n", pctrl->setMode);
        goto err_return;
    }
    prt_dbug("Set AI mode %d success\n", pctrl->setMode);
    /* 配置 AI 采样频率 */
    ret = ioctl(pdev->fd, IOCTL_AI_SET_SAMP_RATE, &pctrl->setSampRate);
    if (ret < 0) {
        prt_erro("Set AI sample rate %dHz failed\n", pctrl->setSampRate);
        goto err_return;
    }
    prt_dbug("Set AI sample rate %dHz success\n", pctrl->setSampRate);
    /* 配置 AI 中断频率 */
    ret = ioctl(pdev->fd, IOCTL_AI_SET_IRQ_RATE, &pctrl->setIrqRate);
    if (ret < 0) {
        prt_erro("Set AI irq rate %dHz failed\n", pctrl->setIrqRate);
        goto err_return;
    }
    prt_dbug("Set AI irq rate %dHz success\n", pctrl->setIrqRate);
    /* 配置 AI 滑动平均窗口 */
    ret = ioctl(pdev->fd, IOCTL_AI_SET_SLID_WIN, &pctrl->setSlidWin);
    if (ret < 0) {
        prt_erro("Set AI slide window %d failed\n", pctrl->setSlidWin);
        goto err_return;
    }
    prt_dbug("Set AI slide window %d success\n", pctrl->setSlidWin);

    /* 配置 AI 量程 */
    for (i = 0; i < pctrl->num; i++) {
        pdev = &pctrl->dev[i];
        /* 检查参数 */
        if (pdev->fd == 0 || 
            aimParam.range[i] < 0 || aimParam.range[i] > AI_RANGE_5V) {
            prt_erro("Invalid parameters for %s\n", __func__);
            ret = -EFAULT;
            goto err_return;
        }
        pdev->setRange = aimParam.range[i];

        /* 配置 AI 量程 */
        ret = ioctl(pdev->fd, IOCTL_AI_SET_RANGE, &pdev->setRange);
        if (ret < 0) {
            prt_erro("Set AI %2d range %d failed\n", pdev->index, pdev->setRange);
            goto err_return;
        }
        prt_dbug("Set AI %2d range %d success\n", pdev->index, pdev->setRange);
    }

    pdev = &pctrl->dev[0];
    /* 开始 AI 采集 */
    ret = ioctl(pdev->fd, IOCTL_AI_START);
    if (ret < 0) {
        prt_erro("Start AI failed\n");
        return -EFAULT;
    }
    prt_dbug("Start AI success\n");

    return 0;

err_return:

    return ret;
}

int AIMRead(int channel, unsigned int *data)
{
    struct AiCtrl_t *pctrl = &AiCtrl;
    struct AiDev_t *pdev = &pctrl->dev[0];
    int ret = 0;

    /* 检查参数 */
    if (!data || 
        channel < 0 || channel >= pctrl->num) {
        prt_erro("Invalid parameters for %s\n", __func__);
        return -EFAULT;
    }
    pdev = &pctrl->dev[channel];
    /* 检查参数 */
    if (pdev->fd == 0) {
        prt_erro("Invalid %s->fd for %s\n", pdev->name, __func__);
        return -EFAULT;
    }
    /* 获取 AI 数值 */
    ret = ioctl(pdev->fd, IOCTL_AI_GET_VAL, &pdev->rawVal);
    if (ret < 0) {
        prt_erro("Get AI %2d value failed\n", pdev->index);
        return -EFAULT;
    }
    prt_dbug("Get AI %2d value %duV\n", pdev->index, pdev->rawVal);
    pdev->val = 1.0 * pdev->rawVal / AI_UV_2_V;
    prt_info("Get AI %2d value %.6lfV\n", pdev->index, pdev->val);
    *data = pdev->rawVal;

    return 0;
}

int AIMReadReal(int channel, int vorc, double *data)
{
    struct AiCtrl_t *pctrl = &AiCtrl;
    struct AiDev_t *pdev = &pctrl->dev[0];
    int ret = 0;

    /* 检查参数 */
    if (!data || 
        channel < 0 || channel >= pctrl->num) {
        prt_erro("Invalid parameters for %s\n", __func__);
        return -EFAULT;
    }
    pdev = &pctrl->dev[channel];
    /* 检查参数 */
    if (pdev->fd == 0) {
        prt_erro("Invalid %s->fd for %s\n", pdev->name, __func__);
        return -EFAULT;
    }
    /* 获取 AI 数值 */
    ret = ioctl(pdev->fd, IOCTL_AI_GET_VAL, &pdev->rawVal);
    if (ret < 0) {
        prt_erro("Get AI %2d value failed\n", pdev->index);
        return -EFAULT;
    }
    prt_dbug("Get AI %2d value %duV\n", pdev->index, pdev->rawVal);
    if (pctrl->type == IET_AC) {
        if (pdev->index < AI_ACM_UCH_NUM) {
            pdev->val = 1.0 * pdev->rawVal / AI_UV_2_V;
            pdev->val = ((pdev->val / AI_ACM_UCH_KVAL) / AI_ACM_SAMP_OHM);      /* 电压计算电流 */
            prt_info("Get AI-U %2d value %.6lfA\n", pdev->index, pdev->val);
            *data = pdev->val;
        } else {
            pdev->val = 1.0 * pdev->rawVal / AI_UV_2_V;
            pdev->val = ((pdev->val / AI_ACM_ICH_KVAL) / AI_ACM_SAMP_OHM);      /* 电压计算电流 */
            prt_info("Get AI-I %2d value %.6lfA\n", pdev->index, pdev->val);
            *data = pdev->val;
        }
    } else {
        if (vorc == AI_VAL_VOLTAGE) {
            pdev->val = 1.0 * pdev->rawVal / AI_UV_2_V;
            prt_info("Get AI %2d value %.6lfV\n", pdev->index, pdev->val);
            *data = pdev->val;
        } else if (AI_VAL_CURRENT) {
            pdev->val = 1.0 * pdev->rawVal / AI_UV_2_MV;
            pdev->val /= AI_SAMP_RESISTOR;      /* 电压计算电流 */
            prt_info("Get AI %2d value %.6lfmA\n", pdev->index, pdev->val);
            *data = pdev->val;
        } else {
            prt_erro("Get AI %2d value failed, value type %d not support\n", pdev->index, vorc);
        }
    }

    return 0;
}

int AIMClose()
{
    struct AiCtrl_t *pctrl = &AiCtrl;
    struct AiDev_t *pdev = &pctrl->dev[0];
    struct ThreadCtrl_t *pthread_irq = &pctrl->irqThread;
    struct ThreadCtrl_t *pthread_tim = &pctrl->dmaThread;
    int ret = 0;
    uint8_t i = 0;
    uint8_t mode = AI_DEV_MOD_NORMAL;

    /* 取消线程 */
    if (pthread_irq->id != 0) {
        pthread_cancel(pthread_irq->id);
        pthread_irq->id = 0;
    }
    /* 取消线程 */
    if (pthread_tim->id != 0) {
        pthread_cancel(pthread_tim->id);
        pthread_tim->id = 0;
    }

    if (pctrl->setMode == AI_DEV_MOD_IRQ || 
        pctrl->setMode == AI_DEV_MOD_DMA) {
        /* 检查参数 */
        if (pdev->fd == 0) {
            prt_erro("Invalid %s->fd for %s\n", pdev->name, __func__);
            return -EFAULT;
        }
        /* 配置 AI 模式 */
        ret = ioctl(pdev->fd, IOCTL_AI_SET_MODE, &mode);
        if (ret < 0) {
            prt_erro("Set AI mode %d failed\n", mode);
            return -EFAULT;
        }
        prt_dbug("Set AI mode %d success\n", mode);
        /* 停止 AI 采集 */
        ret = ioctl(pdev->fd, IOCTL_AI_STOP);
        if (ret < 0) {
            prt_erro("Stop AI failed\n");
            return -EFAULT;
        }
        prt_dbug("Stop AI success\n");
    }

    for (i = 0; i < pctrl->num; i++) {
        pdev = &pctrl->dev[i];
        /* 检查参数 */
        if (pdev->fd == 0) {
            prt_erro("Invalid %s->fd for %s\n", pdev->name, __func__);
            return -EFAULT;
        }
        /* 关闭设备 */
        ret = close(pdev->fd);
        if (ret != 0) {
            prt_erro("Close %s failed\n", pdev->path);
            return -EFAULT;
        }
        pdev->fd = 0;
        prt_dbug("Close %s success\n", pdev->path);
    }

    return 0;
}

/* 注册中断回调函数 */
void registerIrqCallback(IrqCallbackFunction callback)
{
    struct AiCtrl_t *pctrl = &AiCtrl;

    /* 检查参数 */
    if (!callback) {
        prt_erro("Invalid parameters for %s\n", __func__);
        return;
    }
    /* 注册回调 */
    pctrl->irqCallback = callback;
    prt_dbug("Register irq callback success\n");
}

/* 注册 DMA 回调函数 */
void registerDmaCallback(DmaCallbackFunction callback)
{
    struct AiCtrl_t *pctrl = &AiCtrl;

    /* 检查参数 */
    if (!callback) {
        prt_erro("Invalid parameters for %s\n", __func__);
        return;
    }
    /* 注册回调 */
    pctrl->dmaCallback = callback;
    prt_dbug("Register dam callback success\n");
}

/* 获取驱动版本号 */
int AIMGetDrvVer()
{
    struct AiCtrl_t *pctrl = &AiCtrl;

    prt_dbug("%s %d.%d.%d\n", __func__, ((pctrl->drvVer >> 24) & 0xFF), 
             ((pctrl->drvVer >> 16) & 0xFF), (pctrl->drvVer & 0xFFFF));

    return (int)(pctrl->drvVer >> 16);
}

/* 获取 FPGA 版本号 */
int AIMGetFpgaVer()
{
    struct AiCtrl_t *pctrl = &AiCtrl;

    prt_dbug("%s %d.%d\n", __func__, ((pctrl->fpgaVer >> 8) & 0xFF), 
             (pctrl->fpgaVer & 0xFF));

    return (int)(pctrl->fpgaVer);
}

/* 获取动态库版本号 */
int AIMGetLibVer()
{
    struct AiCtrl_t *pctrl = &AiCtrl;

    prt_dbug("%s %d.%d.%d\n", __func__, ((pctrl->libVer >> 24) & 0xFF), 
             ((pctrl->libVer >> 16) & 0xFF), (pctrl->libVer & 0xFFFF));

    return (int)(pctrl->libVer >> 16);
}
